package org.ccay.excel.importer.service.impl.internal;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.ClassUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import org.ccay.core.exception.ApplicationException;
import org.ccay.core.io.FileStoreType;
import org.ccay.core.ioc.Ccay;
import org.ccay.core.log.ILogger;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.util.StreamUtil;
import org.ccay.core.util.StringUtil;
import org.ccay.excel.exception.ExcelImportException;
import org.ccay.excel.importer.ExcelImportConstants;
import org.ccay.excel.importer.IExcelDataProcessor;
import org.ccay.excel.importer.IExcelImportContext;
import org.ccay.excel.importer.IExcelImportProcessBefore;
import org.ccay.excel.importer.ITitleMapper;
import org.ccay.excel.importer.RowData;
import org.ccay.excel.importer.service.IExcelDataConsumer;
import org.ccay.excel.meta.ColumnMeta;
import org.ccay.excel.meta.ExcelMeta;
import org.ccay.excel.meta.IDynamicExcelMetaProvider;
import org.ccay.excel.meta.SheetMeta;
import org.ccay.excel.util.impl.ExcelUtil;
import org.ccay.registry.util.RegistryQueryUtil;
import org.ccay.vfs.ApacheVFSFileObject;

/**
 * Excel XML文件处理器，使用StAX解析XML文件
 * 
 * @author chaowangbang
 * @since Mar 19, 2012
 */
public class ExcelStreamReaderSax {

	private ILogger log = CcayLoggerFactory.getLogger(ExcelStreamReaderSax.class);
	
	// 导入数据的BetchSize，最大限制200
	private static int MAX_BATCH_SIZE = 1000;

	private ExcelImportContext context;

	/** 字符串共享表 **/
	private SharedStringsTable sst;
	/** 样式表**/
	private StylesTable stylesTable;

	private int titleRowIndex = -1; // 标题行的索引行号
	private int dataRowIndex = -1; // 数据起始行的行号
	
	private int endDataRowIndex = -1; // 数据结束行的行号

	private int currentRowIndex = -1; // 当前索引行号

	/** 列的游标 **/
	private int cursorColIndex; // 当前列的游标

	private Map<String, String> titleNameCellNoMap = null;// titleName  cellNO  map
	
	private Map<String, Integer> cellNoCellIndexMap = null;// cellNO  cellIndex  map

	private String currentColNo;// 当前处理的列no

	// 日期格式
	//private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	
	private XMLReader saxParser;
	
	private String colWipe;	//是否去除空格

	private int colCount;

	private int batchSize = 0;
	
	private String[] colsNO = null;

	private RowData rowData = null;

	private List<RowData> rowDatas = new ArrayList<RowData>(
			ExcelImportConstants.BATCH_IMPORT_COUNT);

	private IExcelDataProcessor excelValidator = new ExcelValidator();

	private IExcelDataProcessor voConverter = null;

	private IExcelDataProcessor dataConsumer = new ExcelDataConsumer();
	
	

	/**
	 * @param context
	 * @param monitor
	 */
	public ExcelStreamReaderSax(ExcelImportContext context) {
		this.context = context;
	}

	/**
	 * 处理Excel文件
	 * 
	 * @author chaowangbang
	 * @since Mar 22, 2012
	 * @throws ApplicationException
	 */
	public void process() throws ApplicationException {
		//处理前置的逻辑
		processDynamicProvider();
		
		//已归档文件
		ApacheVFSFileObject archiveFile = new ApacheVFSFileObject(ExcelUtil.VFS_MODULE_EXCEL,
				context.getRequest().getFilePath(), FileStoreType.ARCHIVE);
		
		OPCPackage pkg = null;
		// 流未关闭问题
		List<InputStream> closeStreamList = new ArrayList<InputStream>();
		//end add
		try {
			pkg = OPCPackage.open(archiveFile.getInputStream());
			XSSFReader xssfReader = new XSSFReader(pkg);

			this.sst = xssfReader.getSharedStringsTable();
			this.stylesTable = xssfReader.getStylesTable();
			
			List<SheetMeta> sheetMetas = this.context.getExcelMeta().getSheetList();
			// 元数据中定义的Sheet必须要包含在Excel文件中
			checkMetaDefinitions((SheetIterator)xssfReader.getSheetsData(),sheetMetas);
			
			//处理循环
			processSheetForList(xssfReader,closeStreamList);
			
		} catch (InvalidFormatException e) {
			// 无效的excel文件格式
			throw new ExcelImportException(
					ExcelImportConstants.INVALID_EXCEL_FORMAT, e);
		} catch (IOException e) {
			// 解析Excel文件的过程中发生错误
			throw new ExcelImportException(ExcelImportConstants.PARSE_FAIL, e);
		//begin update hufeng 00214522  2013/8/21 流未关闭问题
		}catch(RuntimeException e){
			// 解析Excel文件的过程中发生错误
			throw new ExcelImportException(ExcelImportConstants.PARSE_FAIL, e);
		//end update
		} catch (OpenXML4JException e) {
			// 解析Excel文件的过程中发生错误
			throw new ExcelImportException(ExcelImportConstants.PARSE_FAIL, e);
		} catch (SAXException e) {
			// 解析Excel文件的过程中发生错误
			throw new ExcelImportException(ExcelImportConstants.PARSE_FAIL, e);
		} finally {
			StreamUtil.closeStreams(pkg);
			for (InputStream sheet :closeStreamList) {
				StreamUtil.closeStreams(sheet);
			}
		}
	}
	
	/**
	 * 处理前置bean问题
	 * @throws ApplicationException
	 * Created 2013-9-16
	 * @author chaowangbang
	 */
	private void processDynamicProvider() throws ApplicationException{
		/**
		 *查找excel解析器，动态处理导入模板
		 */
		IExcelImportProcessBefore processBefore = 
				ExcelUtil.getImportProcessBefore(context.getRequest().getParameters().get(ExcelImportConstants.EXCEL_IMPORT_PROCESS_BEFORE));
		if(null != processBefore){
			processBefore.processBefore(context);
		}
		
		String dynamicProvider = context.getExcelMeta().getDynamicProvider();
		if(!StringUtil.isNullOrEmpty(dynamicProvider)){
			IDynamicExcelMetaProvider dynamicProviderBean = Ccay.getContext().getBean(dynamicProvider, IDynamicExcelMetaProvider.class);
			ExcelMeta copyExcelMeta = null;
			try {
				copyExcelMeta = context.getExcelMeta().copy();
			} catch (CloneNotSupportedException e) {
				log.error(e);
			}
			copyExcelMeta = dynamicProviderBean.process(copyExcelMeta, context.getRequest().getParameters());
			//把修改过会的mete对象更新到上下文中
			context.setExcelMeta(copyExcelMeta);
		}
	}
	
	/**
	 * 循环处理sheet list
	 * @param xssfReader
	 * @param closeStreamList
	 * @throws InvalidFormatException
	 * @throws IOException
	 * @throws SAXException
	 * @throws ApplicationException
	 * Created 2013-9-16
	 * @author chaowangbang
	 */
	private void processSheetForList(XSSFReader xssfReader,List<InputStream> closeStreamList) throws InvalidFormatException, IOException, SAXException, ApplicationException{
		Iterator<InputStream> sheets = xssfReader.getSheetsData();
		//begin add hufeng 00214522  2013/8/21 流未关闭问题
		Map<String,InputStream> iteratorstreamMap = new HashMap<String,InputStream>();
		while(sheets.hasNext()){
			InputStream sheet = sheets.next();
			closeStreamList.add(sheet);
			iteratorstreamMap.put(((SheetIterator) sheets).getSheetName(),sheet);
		}
		//end add
		/**
		 * 读取解析excle的对象
		 */
		saxParser = fetchSheetParser();
		Set<String> executeSheet =  new HashSet<String>();
		List<SheetMeta> sheetMetas = this.context.getExcelMeta().getSheetList();
		/**
		 * 如果配置中有多个sheet 不同，那么一起执行
		 */
		for(SheetMeta sheetMeta:sheetMetas){
			//判断 如果是需要解析已经处理过的sheet 那么重头开始循环
		    //当前sheet表显示名称
			String sheetDisplayName = this.context.getNameDisplayNameMap().get(sheetMeta.getPartSheetName());
			if(null == sheetDisplayName){
				continue;
			}
			if(executeSheet.contains(sheetDisplayName)){
				executeSheet.remove(sheetDisplayName);
				sheets = xssfReader.getSheetsData();
				//begin add hufeng 00214522  2013/8/21 流未关闭问题
				iteratorstreamMap.clear();
				while(sheets.hasNext()){
					InputStream sheet = sheets.next();
					closeStreamList.add(sheet);
					iteratorstreamMap.put(((SheetIterator) sheets).getSheetName(),sheet);
				}
				//end add
			}
			InputStream sheet = iteratorstreamMap.get(sheetDisplayName);
			try{
				processOneSheet(sheetMeta.getSheetName(), sheet);
				//把执行过的sheet名称保存起来 如果下次还需要执行，那么就要重新读取文件对象数据
				executeSheet.add(sheetDisplayName);
			}finally {
				StreamUtil.closeStreams(sheet);
			}
		}
	}
	
	protected  XMLReader fetchSheetParser() throws SAXException {
			XMLReader parser =
				XMLReaderFactory.createXMLReader(
						"com.sun.org.apache.xerces.internal.parsers.SAXParser"
				);
			ContentHandler handler = new SaxParserSheetHandler();
			parser.setContentHandler(handler);
			parser.setFeature("http://xml.org/sax/features/external-general-entities", false);
			return parser;
	}
	
	/** 
	 * 元数据中定义的Sheet必须要包含在Excel文件中
	 * 	
	 * @author chaowangbang
	 * @since 2012-8-2
	 * @param sheetIter
	 * @throws ExcelImportException
	 */
	protected void checkMetaDefinitions(SheetIterator sheetIter,List<SheetMeta> sheetsInMeta) throws ExcelImportException {
		Set<String> sheetsInExcel = new HashSet<String>();
		Map<String, String> sheetNameMap = new HashMap<String, String>();
		while(sheetIter.hasNext()) {
			sheetIter.next();
			String sheetName = sheetIter.getSheetName();
			if(StringUtil.isNullOrEmpty(sheetName)) {
				continue;
			}
			sheetsInExcel.add(sheetName);
		}
		for(SheetMeta sheetMeta : sheetsInMeta) {
			boolean checkde = false;
			/**
			 * 迭代去name中获取国际化显示名称
			 */
			for(Entry<String, String> disNameEntry:sheetMeta.getLanguageNames().entrySet()){
				//只要其他语种存在也算
				if(sheetsInExcel.contains(disNameEntry.getValue())) {
					checkde = true;
					//放置 sheetname显示sheet的关联显示名称，导入的时候直接获取
					sheetNameMap.put(sheetMeta.getPartSheetName(),disNameEntry.getValue());
					break;
				}else{
					if(!StringUtil.isNullOrEmpty(sheetMeta.getDynamicItem())){
						checkde = true;
					}
				}
			}
			if(!checkde){
				throw new ExcelImportException(ExcelImportConstants.SHEET_NOTFOUND_IN_EXCEL, sheetMeta.getDisplayName());
			}
		}
		this.context.setNameDisplayNameMap(sheetNameMap);
	}

	/**
	 * 导入一个Sheet
	 * 
	 * @author chaowangbang
	 * @since Mar 15, 2012
	 * @param name
	 * @param content
	 * @param context
	 * @param support
	 */
	protected void processOneSheet(String name, InputStream sheetContent) throws ApplicationException {
		// 初始化上下文
		this.initContext(name);
		
		// 开始消费sheet数据
		IExcelDataConsumer dataConsumer = context.getCurrentDataConsumer();
		/**用户在这里可以修改CurrentSheet 这个对象 **/
		dataConsumer.begin(this.context);
		
		SheetMeta sheetMeta = context.getCurrentSheet();

		this.initVOConverter(sheetMeta);
		
		/**
		 * 每个sheee的初始化和重置数据
		 */
		initSpecialRowIndex(sheetMeta, name);
		
		InputSource sheetSource = null;
		try {
			sheetSource = new InputSource(sheetContent);
			
			saxParser.parse(sheetSource);
			// 处理残留数据
			processOneBatchData(this.context);
		} catch (ExcelImportException eex) {
			dataConsumer.fail(this.context);
			throw eex;
		} catch (RuntimeException rex) {
			// 记录错误日志
			log.error(rex);
			dataConsumer.fail(this.context);
			throw rex;
		}catch(Exception ex) {
			// 记录错误日志
			log.error(ex);
			dataConsumer.fail(this.context);
			//判断是否自定义的异常
			if(SAXException.class.isAssignableFrom(ex.getClass())){
				SAXException ex2 = (SAXException) ex;
				if(ExcelImportException.class.isAssignableFrom(ex2.getException().getClass())){
					throw (ApplicationException) ex2.getException();
				}
			}
			throw new ExcelImportException(ExcelImportConstants.EXCEL_PARSING_EXCEPTION,ex);
		}catch(Error er){
			log.error(er);
			dataConsumer.fail(this.context);
			throw er;
		} 

		// 正常结束sheet数据的消费
		dataConsumer.end(this.context);
	}

	/**
	 * 初始化上下文
	 * 
	 * @param name
	 * @throws ApplicationException
	 */
	private void initContext(String name) throws ApplicationException {
		this.context.reset();

		SheetMeta sheetMeta = context.getSheetMeta(name);
		if (sheetMeta == null) {
			// 异常：Excel导入配置文件中没有定义sheet: {0}
			throw new ExcelImportException(
					ExcelImportConstants.SHEET_NOT_FOUND, name);
		}
		this.context.setCurrentSheet(sheetMeta);

		/**
		 * 获取Excel数据的消费类
		 */
		IExcelDataConsumer dataConsumer = context.getExcelDataConsumer(name);
		if (dataConsumer == null) {
			// 异常：Sheet:{0}没有对应的数据消费类
			throw new ExcelImportException(
					ExcelImportConstants.DATACONSUMER_NOT_FOUND, name);
		}
		this.context.setCurrentDataConsumer(dataConsumer);
	}

	/**
	 * 初始化VO转换器
	 * 
	 * @throws ApplicationException
	 */
	private void initVOConverter(SheetMeta sheetMeta)
			throws ApplicationException {
		String voBeanName = sheetMeta.getVoBeanName();
		try {
			Class<?> voClass = ClassUtils.getClass(voBeanName);
			this.voConverter = new VOConvertProcessor(voClass);
		} catch (ClassNotFoundException ex) {
			throw new ExcelImportException(
					ExcelImportConstants.VO_CLASS_NOT_FOUND, ex, voBeanName);
		}
	}

	/**
	 * 初始化标题行和数据行的索引号
	 * 
	 * @param sheetMeta
	 * @param name
	 * @throws ApplicationException
	 */
	private void initSpecialRowIndex(SheetMeta sheetMeta, String name)
			throws ApplicationException {
		//初始化配置信息
		this.titleRowIndex = sheetMeta.getTitleRowIndex();
		this.dataRowIndex = sheetMeta.getDataRowIndex();
		this.endDataRowIndex = sheetMeta.getEndDataRowIndex();
		this.currentRowIndex = -1;
		this.cursorColIndex = -1;
		this.colCount = sheetMeta.getColumns().size();
		// 每个sheet的标题不同数据不同 所以需要初始化 
		this.titleNameCellNoMap = null;
		this.cellNoCellIndexMap = null;
		this.currentColNo =null;
		this.colsNO = new String[this.colCount];
		this.batchSize = sheetMeta.getBatchSize();
		this.colWipe=sheetMeta.getColumnWipe();
		//如果没有设置结束索引号，那么赋值最大
		if(this.endDataRowIndex<=0){
			this.endDataRowIndex = Integer.MAX_VALUE;
		}
		if (this.dataRowIndex < this.titleRowIndex) {
			throw new ExcelImportException(
					ExcelImportConstants.DATAROW_LESSTHAN_TITLEROW, name);
		}
		if (this.endDataRowIndex < this.dataRowIndex) {
			throw new ExcelImportException(
					ExcelImportConstants.ENDDATAROW_LESSTHAN_BEGIN, name);
		}
		// 如果没有设置 那么使用默认值
		if (this.batchSize <= 0) {
			this.batchSize  = RegistryQueryUtil.getIntegerValue(ExcelImportConstants.IMPORT_BATCH_SIZE_PATH);
		}
		
		/**
		 * 如果配置的bachsize大于 限制最大值 那么取最大值
		 */
		// batchSize 的最大取值为 200  linyuning lwx211179
		batchSize = Math.min(batchSize, MAX_BATCH_SIZE);
		
		//如果没有值默认去数据字典取值
		if(StringUtil.isNullOrEmpty(this.colWipe)){
			String registryValue = RegistryQueryUtil.getValue(ExcelImportConstants.COLUMN_WIPE_PATH);
			this.colWipe=registryValue;
		}
		
		log.info("Current batchSize is {0}", this.batchSize);
	}


	/**
	 * 批量处理数据
	 * 
	 * @author chaowangbang
	 * @since Mar 21, 2012
	 * @param rowDatas
	 * @throws ApplicationException
	 */
	protected void processOneBatchData(IExcelImportContext context) throws ApplicationException {
		log.debug("--bgein processOneBatchData");
		context.addProcessedCount(this.rowDatas.size());
		
		// 验证这一批数据
		log.debug("--bgein validRowDatas");
		List<?> validRowDatas = excelValidator.process(this.rowDatas, context);
		log.debug("--end validRowDatas");
		
		// 转换行数据到VO
		log.debug("--bgein voConverter.process");
		List<?> vos = voConverter.process(validRowDatas, context);
		log.debug("--end voConverter.process");
		
		// 批量插入数据
		log.debug("--bgein dataConsumer.process");
		dataConsumer.process(vos, context);
		log.debug("--end dataConsumer.process");
		// 清理已经处理的数据
		rowDatas.clear();
		log.debug("--end processOneBatchData");
	}

	/**
	 * 处理标题行
	 * 
	 * @author chaowangbang
	 * @since Mar 21, 2012
	 * @param rowData
	 * @throws ExcelImportException
	 */
		private void processTitleRow(RowData rowData) throws ExcelImportException {
			Map<String, String> col2TitleMap = new HashMap<String, String>();
			Map<String, String> title2FieldMap = new HashMap<String, String>();
			Map<String, String> field2colMap = new HashMap<String, String>();
			Map<String, String> name2col2Map = new HashMap<String, String>();
			this.colsNO = this.rowData.colsIndex;
			Object[] colsData = rowData.colsData;
			SheetMeta sheetMeta =this.context.getCurrentSheet();
			for (int i = 0; i < this.colsNO.length; i++) {
				String colNo = this.colsNO[i];
				if(colNo == null){
					continue;
				}
				String colName = colsData[i].toString();
				ColumnMeta col = sheetMeta.getColumnByDisplayName(colName);
				if (col == null) {
					// 异常: Sheet({0})中没有发现名称为{0}的列定义
					throw new ExcelImportException(
							ExcelImportConstants.COLUMN_NOT_FOUND,
							sheetMeta.getSheetName(), colName);
				}
				col2TitleMap.put(colNo, colName);
				title2FieldMap.put(colName, col.getFieldName());
				field2colMap.put(col.getFieldName(), colNo);
				name2col2Map.put(colNo, col.getName());
			}
			ITitleMapper titleMapper = new TitleMapper(col2TitleMap,
					title2FieldMap, field2colMap,name2col2Map);
			this.context.setTitleMapper(titleMapper);
		}
		
	class TitleMapper implements ITitleMapper {

		/** 列索引号到标题名称的映射 **/
		private Map<String, String> col2TitleMap = null;

		/** 标题名称到VO属性名称的映射 **/
		private Map<String, String> title2FieldMap = null;

		private Map<String, String> field2colMap = null;

		/** 列索引号对应的列名称**/
		private Map<String, String> name2col2Map = null;
		/**
		 * @param col2TitleMap
		 * @param title2FieldMap
		 */
		public TitleMapper(Map<String, String> col2TitleMap,
				Map<String, String> title2FieldMap,
				Map<String, String> field2colMap,Map<String, String> name2col2Map) {
			this.col2TitleMap = col2TitleMap;
			this.title2FieldMap = title2FieldMap;
			this.field2colMap = field2colMap;
			this.name2col2Map  = name2col2Map;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.ccay.excel.importer.ITitleMapper#getField(java.lang
		 * .String)
		 */
		public String getField(String title) {
			return this.title2FieldMap.get(title);
		}

		public String getCol(String field) {
			return this.field2colMap.get(field);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.ccay.excel.importer.ITitleMapper#getTitle(java.lang
		 * .String)
		 */
		public String getTitle(String col) {
			return this.col2TitleMap.get(col);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.ccay.excel.importer.ITitleMapper#getFieldByColIndex
		 * (java.lang.String)
		 */
		public String getFieldByColIndex(String colIndex) {
			String title = getTitle(colIndex);
			return getField(title);
		}

		public String getName(String col) {
			return this.name2col2Map.get(col);
		}
	}
	
	
	/** 
	 * See org.xml.sax.helpers.DefaultHandler javadocs 
	 */
	class SaxParserSheetHandler extends DefaultHandler {
		private static final String IS_COL_WIPE = "1";
		private String cellValueStr;
		private boolean isString;
		private String dataType;
		private String style = null; // 单元格的样式
		private boolean isValidCell = false; // 单元格的有效性标识
		private boolean isValidRow = false; // 行的有效性标识
		private boolean isEmptyRow = true;//是否是空行

		SaxParserSheetHandler() {
		}
		
		/**
		 * xml文件开始标签
		 */
		public void startElement(String uri, String localName, String name,
				Attributes attributes) throws SAXException {
			// 处理行数据
			if ("row".equals(localName)) { 
				String rowStr = attributes.getValue("r"); 
				if (rowStr == null) {
					return;
				}
				currentRowIndex = Integer.parseInt(rowStr);
				checkValidRow();
				if(!this.isValidRow){
					return;
				}
				// 初始化行数据
				rowData = new RowData(currentRowIndex,colCount,colsNO);
				this.isValidRow = true;
				this.isEmptyRow = true;
			}else if(name.equals("c")) {
				if(!this.isValidRow){
					return;
				}
				// 处理单元元格 c => cell, eg: <c r="B2"
				// s="3"><v>36141</v></c>
				// <c r="B2"s="3"><is><t>cctv077</t></c>
				// <c r="B2"s="3"><f>A:B</f><v>cctv077</v></c>
				// Print the cell reference
				String cellIndex = attributes.getValue("r");
				// 单元格的列号 A B C 
				currentColNo = cellIndex.substring(0,
						cellIndex.indexOf(Integer.toString(currentRowIndex)));
				try {
					checkValidCell();
				} catch (ApplicationException e) {
					throw new SAXException(e);
				}
				if(!this.isValidCell){
					return;
				}
				// Figure out if the value is an index in the SST
				String cellType = attributes.getValue("t");
				this.dataType = cellType;
				this.style = attributes.getValue("s");
				if(cellType != null && cellType.equals("s")) {
					this.isString = true;
				} 
			}
			cellValueStr = "";
		}
		
		/**
		 * xml文件结束标签
		 */
		public void endElement(String uri, String localName, String name)
				throws SAXException {
			if(!this.isValidRow){
				return;
			}
			if ("row".equals(localName)) { // 结束行处理
				//end row方法 存储数据
				try {
					this.processorRowData();
				} catch (ApplicationException e) {
					throw new SAXException(e);
				}
			}else if("c".equals(localName)){
				style = null;
				//列结束
			}else if( name.equals("v") || name.equals("t")) {
				if(!this.isValidCell){
					return;
				}
				//处理单元格结尾事件，获取value
				Object value = processorColValue();
				//存储value值
				this.addColValue(value);
				this.isString = false;
			}
		}
		
		/**
		 * xml文件获取value标签
		 */
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			if(!this.isValidRow){
				return;
			}
			cellValueStr += new String(ch, start, length);
		}
		
		/**
		 * 操作 验证获取的当前标题列 是否需要加入到
		 * 
		 * @param value
		 *            Created 2012-7-24
		 * @author chaowangbang
		 */
		private void addColValue(Object value) {
			// 如果读取的是标题行，那么需要去sheet中验证当前列是否需要读取
			if (currentRowIndex == titleRowIndex) {
				// map对象是空的时创建一个新的空Map
				if (null == titleNameCellNoMap) {
					titleNameCellNoMap = new HashMap<String, String>();
					cellNoCellIndexMap = new HashMap<String, Integer>();
				}
				String columnName = null;
				if(value != null){
					columnName = value.toString();
				}
				// 验证当前Sheet表是否在xml文件中配置，如果配置了才读取
				if (null != context.getCurrentSheet().getColumnByDisplayName(columnName)) {
					// 判断这列数据是否已经读取，excel中可以列名相同，如果读取，那么不操作
					if (!titleNameCellNoMap.containsKey(columnName)) {
						cursorColIndex ++;
						titleNameCellNoMap.put(columnName, currentColNo);
						cellNoCellIndexMap.put(currentColNo, cursorColIndex);
						rowData.colsData[cursorColIndex] = value;
						rowData.colsIndex[cursorColIndex]= currentColNo;
					}
				}
				// 如果是读取数据为空，那么直接添加到数据行数据中，因为再前面开始的时候做了验证
			} else {
				if(null != value && !StringUtil.isNullOrEmpty(value.toString())) {
					this.isEmptyRow = false;
				}
				cursorColIndex ++;
				rowData.colsData[cellNoCellIndexMap.get(currentColNo)] = value;
			}
		}
		/**
		 * 获取日志格式
		 * @param s
		 * @return
		 * Created 2013-7-23
		 * @author chaowangbang
		 */
		private boolean isDateFormat(String s) {
			CellStyle style = getCellStyle(s);
			if (style == null) {
				return false;
			}

			int formatIndex = style.getDataFormat();
			String formatString = style.getDataFormatString();
			return DateUtil.isADateFormat(formatIndex, formatString);
		}
		/**
		 * 获取当前的样式集合
		 * @param s
		 * @return
		 * Created 2013-7-23
		 * @author chaowangbang
		 */
		private XSSFCellStyle getCellStyle(String s) {
			if (s == null) {
				return null;
			}
			if (stylesTable.getNumCellStyles() > 0) {
				return stylesTable.getStyleAt(Integer.parseInt(s));
			}

			return null;
		}
		
		
		/**
		 * 检查是否有效的行数据，无效的行数据提前结束以提高性能
		 * @param reader
		 * @param eventType
		 * @return
		 * Created 2012-9-9
		 * @author chaowangbang
		 */
		private void checkValidRow(){
			//当前索引行号大于数据结束索引行号， 那么这些数据都将不处处理， 直接返回
			if(currentRowIndex > endDataRowIndex){
				this.isValidRow = false;
				return;
			}
			//当前索引行号小于title索引行号 或当前索引行号大于title并且小于data开始索引行号
			if(currentRowIndex < titleRowIndex || 
					(currentRowIndex > titleRowIndex && currentRowIndex < dataRowIndex) ){
				//如果数据都是无效的，并且执行的不是行节点  那么直接返回
				this.isValidRow = false;
				return;
			}
			this.isValidRow = true;
		}
		/**
		 * 检查当前列数据是否 xml文件配置需要的数据
		 * 
		 * @param colIndex
		 *            Created 2012-7-24
		 * @author chaowangbang
		 * @throws ExcelImportException 
		 */
		private void checkValidCell() throws ApplicationException{
			isValidCell = true;
			// 如果是读取标题的时候按照顺序读取 不做缺少数据对比
			if (currentRowIndex == titleRowIndex) {
				// 操作的列数据累加 一定要小于xml文件配置的列数据 否则或略
				if (cursorColIndex < colCount) {
					isValidCell =  true;
					return;
				}
				// 操作列数据已经满足了xml配置的列 其余的属于多余数据则忽略处理
				isValidCell = false;
				return;
			}
			if(null  == titleNameCellNoMap){
				throw new ExcelImportException(ExcelImportConstants.SHEET_TEMPLATE_NO_TITLE_IN_EXCEL,titleRowIndex,context.getCurrentSheet().getSheetName());
			}
			// 读取的是数据行，  这时候titleRowMap肯定不为空，如果标题中不存在当前的列 那么跳过
			if (!titleNameCellNoMap.containsValue(currentColNo)) {
				isValidCell = false;
				return;
			}
			return;
		}
		/**
		 * 处理列value
		 * Created 2013-7-26
		 * @author chaowangbang
		 */
		private Object processorColValue(){
			Object cellValue = null;
			// 导入默认是去除空格的，但是数据字典Ccay.Excel.ColumnWipe配置为1，则不去空格。
			if (!IS_COL_WIPE.equals(colWipe)) {
				cellValueStr = cellValueStr.trim();
			}
			if(this.isString) {
				int idx = Integer.parseInt(cellValueStr);
				// begin modify by zwx304259 SP20 导入默认是去除空格的，但是数据字典Ccay.Excel.ColumnWipe配置为1，则不去空格。
				if (!IS_COL_WIPE.equals(colWipe)) {
					cellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString().toString().trim();
				}
				else
				{
					cellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString().toString();
				}
				// end modify by zwx304259
			}else if (isDateFormat(style) && !"str".equals(dataType)) { // 是否是日期类型
				// 如果是日期型格式，转换成日期
				try {
					double d = Double.parseDouble(cellValueStr);
					cellValue = DateUtil.getJavaDate(d);
				} catch (Exception e) {
					log.error("date type convert fail! value:" + cellValueStr);
					cellValue = null;
				}
			}else{
				cellValue = cellValueStr;
			}
			//如果是数字以.0结尾 那么前面取前面的整数
			//新版本中下载的导入模板支持type=int类型数据，会自动格式化为整数。  Modity by linyuning lWX211179 2015-03-30
//			if(!isDateFormat(style) && StringUtil.isNumeric(cellValue.toString()) && cellValue.toString().endsWith(".0")){
//				cellValue = cellValue.toString().substring(0, cellValue.toString().length()-2);
//			}
			return cellValue;
		}
		/**
		 * 结束行处处理
		 * Created 2013-7-26
		 * @author chaowangbang
		 * @throws ApplicationException 
		 */
		private void processorRowData() throws ApplicationException{
				if (currentRowIndex == titleRowIndex) { // 标题索引
					if(cursorColIndex < colCount -1){
						String notColNames = getNoExistCol();
						if(!StringUtil.isNullOrEmpty(notColNames)){
							throw new ExcelImportException(ExcelImportConstants.SHEET_TEMPLATE_ERROE_IN_EXCEL,context.getCurrentSheet().getSheetName(),notColNames);
						}
					}
					processTitleRow(rowData);
				} else if (currentRowIndex >= dataRowIndex) { // 数据索引
					// 添加到行数据列表中
					if(!this.isEmptyRow){
						rowDatas.add(rowData);
					}
					if (rowDatas.size() >= batchSize) {
						processOneBatchData(context);
					}
				}
				// 清理数据
				cursorColIndex = 0;
				this.isValidCell = false;
		}
		/**
		 * 如果列数少于配置列数 那么获取哪些列不存在
		 * @return
		 */
		private String getNoExistCol(){
			StringBuffer colName = new StringBuffer();
			for(ColumnMeta col:context.getCurrentSheet().getColumns()){
				if(!titleNameCellNoMap.containsKey(col.getDisplayName()) && StringUtil.isNullOrEmpty(col.getDynamicItem())){
					colName.append(col.getDisplayName()+",");
				}
			}
			//删除最后的分隔符号
			if(colName.length()>1){
				colName.delete(colName.length()-1, colName.length());
			}
			return colName.toString();
		}


	}

}
